package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.*;
import com.example.exception.BusinessException;
import com.example.mapper.*;
import com.example.service.StudyRoomReservationService;
import com.example.service.OperationLogService;
import com.example.util.DistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;

import java.sql.Time;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

/**
 * @author HP
 * @description 针对表【study_room_reservation】的数据库操作Service实现
 * @createDate 2025-08-26 19:40:00
 */

@Slf4j
@Service
public class StudyRoomReservationServiceImpl extends ServiceImpl<StudyRoomReservationMapper, StudyRoomReservation>
        implements StudyRoomReservationService {

    @Resource
    private StudyRoomReservationMapper studyRoomReservationMapper;

    @Resource
    private SeatMapper seatMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoomMapper roomMapper;

    @Resource
    private OperationLogService operationLogService;

    @Resource
    private DistributedLock distributedLock;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createReservation(Long userId, Long seatId, Date startTime, Date endTime) {
        
        // 使用分布式锁防止并发预约冲突
        try {
            return distributedLock.executeWithLock(seatId, 10, () -> {
                return doCreateReservation(userId, seatId, startTime, endTime);
            });
        } catch (Exception e) {
            if (e.getMessage().contains("获取座位锁失败")) {
                throw new BusinessException("系统繁忙，请稍后重试");
            }
            throw new BusinessException(e.getMessage());
        }
    }
    
    /**
     * 实际执行创建预约的方法（在锁内执行）
     */
    private boolean doCreateReservation(Long userId, Long seatId, Date startTime, Date endTime) {
        
        // 1. 参数验证
        if (userId == null || seatId == null || startTime == null || endTime == null) {
            throw new BusinessException("必填参数不能为空");
        }
        LocalTime nowTime = LocalTime.now();
        LocalTime startLocalTime = startTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalTime();
        LocalTime endLocalTime = endTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalTime();
        if (startTime.after(endTime)) {
            throw new BusinessException("开始时间不能晚于结束时间");
        }

        // 检查开始时间是否早于当前时间

        log.info("nowTime: " + nowTime);
        log.info("startTime: " + startTime);
        if (startLocalTime.isBefore(nowTime)) {
            throw new BusinessException("开始时间不能早于当前时间");
        }

        // 检查预约时长限制（最长12小时）
        long duration = endTime.getTime() - startTime.getTime();
        long maxDuration = 12 * 60 * 60 * 1000; // 12小时
        if (duration > maxDuration) {
            throw new BusinessException("单次预约时长不能超过12小时");
        }

        // 2. 验证用户和座位存在性
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        if (user.getReservationDisabled() != null && user.getReservationDisabled() == 1) {
            throw new BusinessException("用户预约功能已被禁用");
        }

        Seat seat = seatMapper.selectById(seatId);
        if (seat == null) {
            throw new BusinessException("座位不存在");
        }

        if (seat.getSeatStatus() == 3) {
            throw new BusinessException("座位正在维护中，暂不可预约");
        }

        // 3. 检查时间冲突
        if (checkTimeConflict(seatId, startTime, endTime, null)) {
            throw new BusinessException("该时间段座位已被预约，请选择其他时间");
        }

        // 4. 检查用户是否已有有效预约（一次只能有一个预约）
        Date today = new Date();
        
        QueryWrapper<StudyRoomReservation> activeReservationWrapper = new QueryWrapper<>();
        activeReservationWrapper.eq("user_id", userId)
                .in("reservation_status", 0, 1) // 0:待签到, 1:已签到
                .and(wrapper -> wrapper
                        // 今天的预约且结束时间未到
                        .apply("DATE(reservation_time) = DATE({0})", today)
                        .apply("end_time >= {0}", nowTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .or()
                        // 或者未来日期的预约
                        .apply("DATE(reservation_time) > DATE({0})", today)
                );
        
        long activeReservationCount = studyRoomReservationMapper.selectCount(activeReservationWrapper);
        if (activeReservationCount > 0) {
            throw new BusinessException("您已有有效预约，请先完成或取消当前预约后再预约新的时段");
        }


        // 6. 创建预约记录
        StudyRoomReservation reservation = new StudyRoomReservation();
        reservation.setSeatId(seatId);
        reservation.setUserId(userId);
        reservation.setReservationTime(new Date());
        reservation.setStartTime(startTime);
        reservation.setEndTime(endTime);
        reservation.setReservationStatus(0); // 待签到

        int insertResult = studyRoomReservationMapper.insert(reservation);
        if (insertResult <= 0) {
            throw new BusinessException("创建预约记录失败");
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelReservation(Long reservationId, Long userId, Long operatorId, 
                                   String operatorName, String ip) {
        
        if (reservationId == null || userId == null) {
            throw new BusinessException("预约ID和用户ID不能为空");
        }

        // 1. 验证预约记录存在
        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预约记录不存在");
        }

        // 使用分布式锁防止并发取消冲突
        try {
            return distributedLock.executeWithLock(reservation.getSeatId(), 10, () -> {
                return doCancelReservation(reservationId, userId, operatorId, operatorName, ip);
            });
        } catch (Exception e) {
            if (e.getMessage().contains("获取座位锁失败")) {
                throw new BusinessException("系统繁忙，请稍后重试");
            }
            throw new BusinessException(e.getMessage());
        }
    }
    
    /**
     * 实际执行取消预约的方法（在锁内执行）
     */
    private boolean doCancelReservation(Long reservationId, Long userId, Long operatorId, 
                                      String operatorName, String ip) {
        
        // 重新获取预约记录确保数据最新
        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预约记录不存在");
        }

        // 验证用户权限
        if (!reservation.getUserId().equals(userId)) {
            throw new BusinessException("只能取消自己的预约");
        }

        // 验证预约状态
        if (reservation.getReservationStatus() == 2) {
            throw new BusinessException("预约已取消");
        }

        if (reservation.getReservationStatus() == 1) {
            throw new BusinessException("已签到的预约不能取消");
        }

        // 验证取消时间限制（开始前30分钟可取消）
        LocalTime nowTime = LocalTime.now();
        LocalTime startLocalTime = LocalTime.ofInstant(
                reservation.getStartTime().toInstant(),
                ZoneId.systemDefault()
        );

        log.info("当前时间: {}", nowTime);
        log.info("预约开始时间: {}", startLocalTime);

        // 计算时间差
        long minutesDifference = ChronoUnit.MINUTES.between(nowTime, startLocalTime);

        if (minutesDifference < 30) {
            throw new BusinessException("预约开始前30分钟内不允许取消");
        }

        // 更新预约状态
        reservation.setReservationStatus(2); // 已取消
        int updateResult = studyRoomReservationMapper.updateById(reservation);
        if (updateResult <= 0) {
            throw new BusinessException("取消预约失败");
        }

        // 释放座位状态
        Seat seat = seatMapper.selectById(reservation.getSeatId());
        if (seat != null) {
            seat.setSeatStatus(1); // 有空闲
            seatMapper.updateById(seat);
        }

        // 记录操作日志
        operationLogService.recordLog(operatorId, reservation.getSeatId(), 3, // 实体类型：3-座位
                "用户取消预约");

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adminCancelReservation(Long reservationId, String reason, Long operatorId, 
                                        String operatorName, String ip) {
        
        if (reservationId == null || operatorId == null) {
            throw new BusinessException("预约ID和操作人ID不能为空");
        }

        // 1. 验证预约记录存在
        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预约记录不存在");
        }

        // 2. 验证预约状态
        if (reservation.getReservationStatus() == 2) {
            throw new BusinessException("预约已取消");
        }

        // 3. 更新预约状态（管理员取消无时间限制）
        reservation.setReservationStatus(2); // 已取消
        int updateResult = studyRoomReservationMapper.updateById(reservation);
        if (updateResult <= 0) {
            throw new BusinessException("取消预约失败");
        }

        // 4. 释放座位状态
        Seat seat = seatMapper.selectById(reservation.getSeatId());
        if (seat != null) {
            seat.setSeatStatus(1); // 有空闲
            seatMapper.updateById(seat);
        }

        // 5. 记录操作日志
        String logReason = reason != null ? reason : "管理员强制取消";
        operationLogService.recordLog(operatorId, reservation.getSeatId(), 3, // 实体类型：3-座位
                String.format("管理员取消预约，原因：%s", logReason));

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean checkInReservation(Long reservationId, Long userId) {
        
        if (reservationId == null || userId == null) {
            throw new BusinessException("预约ID和用户ID不能为空");
        }

        // 1. 验证预约记录存在
        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预约记录不存在");
        }

        // 2. 验证用户权限
        if (!reservation.getUserId().equals(userId)) {
            throw new BusinessException("只能签到自己的预约");
        }

        // 3. 验证预约状态
        if (reservation.getReservationStatus() == 2) {
            throw new BusinessException("预约已取消，无法签到");
        }

        if (reservation.getReservationStatus() == 1) {
            throw new BusinessException("预约已签到");
        }

        if (reservation.getReservationStatus() == 3) {
            throw new BusinessException("预约已超时，无法签到");
        }

        // 4. 检查是否为今天的预约
        Calendar cal = Calendar.getInstance();
        cal.setTime(reservation.getReservationTime());
        Calendar today = Calendar.getInstance();
        
        if (cal.get(Calendar.YEAR) != today.get(Calendar.YEAR) ||
            cal.get(Calendar.DAY_OF_YEAR) != today.get(Calendar.DAY_OF_YEAR)) {
            throw new BusinessException("只能对今天的预约进行签到");
        }

        // 5. 验证签到时间窗口（预约开始前30分钟内可签到）
        LocalTime nowTime = LocalTime.now();
        LocalTime startTime = reservation.getStartTime().toInstant()
                .atZone(ZoneId.systemDefault()).toLocalTime();

        LocalTime checkInStart = startTime.minusMinutes(30);
        
        if (nowTime.isBefore(checkInStart)) {
            throw new BusinessException("签到时间未到（预约开始前30分钟内可签到）");
        }

        if (nowTime.isAfter(startTime)) {
            throw new BusinessException("签到时间已过（只能在预约开始前30分钟内签到）");
        }

        // 6. 更新预约状态
        reservation.setReservationStatus(1); // 已签到
        reservation.setSignTime(new Date()); // 记录完整的签到时间戳
        
        int updateResult = studyRoomReservationMapper.updateById(reservation);
        if (updateResult <= 0) {
            throw new BusinessException("签到失败");
        }

        // 7. 更新座位状态为已占用（可选）
        Seat seat = seatMapper.selectById(reservation.getSeatId());
        if (seat != null && seat.getSeatStatus() != 2) {
            seat.setSeatStatus(2); // 设置为已约满/已占用
            seatMapper.updateById(seat);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adminCheckInReservation(Long reservationId, Long operatorId, String operatorName, String ip) {
        
        if (reservationId == null || operatorId == null) {
            throw new BusinessException("预约ID和操作人ID不能为空");
        }

        // 1. 验证预约记录存在
        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            throw new BusinessException("预约记录不存在");
        }

        // 2. 验证预约状态
        if (reservation.getReservationStatus() == 2) {
            throw new BusinessException("预约已取消，无法签到");
        }

        if (reservation.getReservationStatus() == 1) {
            throw new BusinessException("预约已签到");
        }

        // 3. 更新预约状态（管理员签到无时间限制）
        reservation.setReservationStatus(1); // 已签到
        reservation.setSignTime(new Date());
        
        int updateResult = studyRoomReservationMapper.updateById(reservation);
        if (updateResult <= 0) {
            throw new BusinessException("签到失败");
        }

        // 4. 更新座位状态
        Seat seat = seatMapper.selectById(reservation.getSeatId());
        if (seat != null && seat.getSeatStatus() != 2) {
            seat.setSeatStatus(2); // 设置为已约满/已占用
            seatMapper.updateById(seat);
        }

        // 5. 记录详细的操作日志
        User reservationUser = userMapper.selectById(reservation.getUserId());
        String userInfo = reservationUser != null ? reservationUser.getUsername() : "未知用户";
        
        operationLogService.recordLog(operatorId, reservation.getSeatId(), 3, // 实体类型：3-座位
                String.format("管理员代替用户签到 - 预约用户: %s, 座位: %d, 操作人: %s", 
                        userInfo, reservation.getSeatId(), operatorName));

        return true;
    }

    @Override
    public List<StudyRoomReservation> getUserReservations(Long userId) {
        
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }

        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId)
                .orderByDesc("reservation_time");
        
        return studyRoomReservationMapper.selectList(queryWrapper);
    }

    @Override
    public List<StudyRoomReservation> getSeatReservations(Long seatId, Date startDate, Date endDate) {
        
        if (seatId == null) {
            throw new BusinessException("座位ID不能为空");
        }

        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("seat_id", seatId);
        
        if (startDate != null && endDate != null) {
            // 使用reservation_time字段进行日期过滤，而不是TIME字段
            queryWrapper.between("reservation_time", startDate, endDate);
        }
        
        queryWrapper.orderByAsc("start_time");
        
        return studyRoomReservationMapper.selectList(queryWrapper);
    }

    @Override
    public boolean checkTimeConflict(Long seatId, Date startTime, Date endTime, Long excludeReservationId) {
        
        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("seat_id", seatId)
                .ne("reservation_status", 2); // 排除已取消的预约
        
        // 排除指定的预约ID（用于更新时检查）
        if (excludeReservationId != null) {
            queryWrapper.ne("id", excludeReservationId);
        }

        // 先检查当天的预约，然后再检查时间冲突
        Date today = new Date();
        queryWrapper.apply("DATE(reservation_time) = DATE({0})", today);
        
        // 时间冲突检查：新预约的开始时间 < 现有预约的结束时间 AND 新预约的结束时间 > 现有预约的开始时间
        LocalTime startLocalTime = startTime.toInstant()
                .atZone(ZoneId.systemDefault()).toLocalTime();
        LocalTime endLocalTime = endTime.toInstant()
                .atZone(ZoneId.systemDefault()).toLocalTime();

        queryWrapper.and(wrapper -> wrapper
                .apply("start_time < {0}", endLocalTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                .apply("end_time > {0}", startLocalTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
        );

        long count = studyRoomReservationMapper.selectCount(queryWrapper);
        return count > 0;
    }

    @Override
    public Map<String, Object> getReservationStatistics(Long seatId, Date date) {
        
        Map<String, Object> statistics = new HashMap<>();
        
        if (date == null) {
            date = new Date();
        }

        // 设置查询日期范围
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startOfDay = cal.getTime();

        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        Date endOfDay = cal.getTime();

        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        // 改用reservation_time字段进行日期过滤
        queryWrapper.between("reservation_time", startOfDay, endOfDay);
        
        if (seatId != null) {
            queryWrapper.eq("seat_id", seatId);
        }

        // 总预约数
        long totalReservations = studyRoomReservationMapper.selectCount(queryWrapper);
        statistics.put("totalReservations", totalReservations);

        // 已签到数
        QueryWrapper<StudyRoomReservation> checkedInWrapper = queryWrapper.clone();
        checkedInWrapper.eq("reservation_status", 1);
        long checkedInCount = studyRoomReservationMapper.selectCount(checkedInWrapper);
        statistics.put("checkedInCount", checkedInCount);

        // 已取消数
        QueryWrapper<StudyRoomReservation> cancelledWrapper = queryWrapper.clone();
        cancelledWrapper.eq("reservation_status", 2);
        long cancelledCount = studyRoomReservationMapper.selectCount(cancelledWrapper);
        statistics.put("cancelledCount", cancelledCount);

        // 待签到数
        QueryWrapper<StudyRoomReservation> pendingWrapper = queryWrapper.clone();
        pendingWrapper.eq("reservation_status", 0);
        long pendingCount = studyRoomReservationMapper.selectCount(pendingWrapper);
        statistics.put("pendingCount", pendingCount);

        // 签到率
        double checkInRate = totalReservations > 0 ? 
                (double) checkedInCount / totalReservations * 100 : 0.0;
        statistics.put("checkInRate", String.format("%.1f%%", checkInRate));

        return statistics;
    }

    @Override
    public Map<String, Object> canCancelReservation(Long reservationId, Long userId) {
        
        Map<String, Object> result = new HashMap<>();
        result.put("canCancel", false);
        result.put("reason", "");

        if (reservationId == null || userId == null) {
            result.put("reason", "参数不能为空");
            return result;
        }

        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            result.put("reason", "预约记录不存在");
            return result;
        }

        if (!reservation.getUserId().equals(userId)) {
            result.put("reason", "只能取消自己的预约");
            return result;
        }

        if (reservation.getReservationStatus() == 2) {
            result.put("reason", "预约已取消");
            return result;
        }

        if (reservation.getReservationStatus() == 1) {
            result.put("reason", "已签到的预约不能取消");
            return result;
        }

        // 检查时间限制（只有今天的预约才需要检查时间限制）
        Calendar cal = Calendar.getInstance();
        cal.setTime(reservation.getReservationTime());
        Calendar today = Calendar.getInstance();
        
        // 如果不是今天的预约，可以取消
        if (cal.get(Calendar.YEAR) != today.get(Calendar.YEAR) ||
            cal.get(Calendar.DAY_OF_YEAR) != today.get(Calendar.DAY_OF_YEAR)) {
            result.put("canCancel", true);
            return result;
        }
        
        // 今天的预约需要检查时间限制
        LocalTime nowTime = LocalTime.now();
        LocalTime startTime = reservation.getStartTime().toInstant()
                .atZone(ZoneId.systemDefault()).toLocalTime();
        
        LocalTime cancelDeadline = startTime.minusMinutes(30);
        
        if (nowTime.isAfter(cancelDeadline)) {
            result.put("reason", "预约开始前30分钟内不允许取消");
            return result;
        }

        result.put("canCancel", true);
        return result;
    }

    @Override
    public Map<String, Object> canCheckInReservation(Long reservationId, Long userId) {
        
        Map<String, Object> result = new HashMap<>();
        result.put("canCheckIn", false);
        result.put("reason", "");

        if (reservationId == null || userId == null) {
            result.put("reason", "参数不能为空");
            return result;
        }

        StudyRoomReservation reservation = studyRoomReservationMapper.selectById(reservationId);
        if (reservation == null) {
            result.put("reason", "预约记录不存在");
            return result;
        }

        if (!reservation.getUserId().equals(userId)) {
            result.put("reason", "只能签到自己的预约");
            return result;
        }

        if (reservation.getReservationStatus() == 2) {
            result.put("reason", "预约已取消，无法签到");
            return result;
        }

        if (reservation.getReservationStatus() == 1) {
            result.put("reason", "预约已签到");
            return result;
        }

        if (reservation.getReservationStatus() == 3) {
            result.put("reason", "预约已超时，无法签到");
            return result;
        }

        // 检查是否为今天的预约
        Calendar cal = Calendar.getInstance();
        cal.setTime(reservation.getReservationTime());
        Calendar today = Calendar.getInstance();
        
        if (cal.get(Calendar.YEAR) != today.get(Calendar.YEAR) ||
            cal.get(Calendar.DAY_OF_YEAR) != today.get(Calendar.DAY_OF_YEAR)) {
            result.put("reason", "只能对今天的预约进行签到");
            return result;
        }
        
        // 检查签到时间窗口（预约开始前30分钟内可签到）
        LocalTime nowTime = LocalTime.now();
        LocalTime startTime = reservation.getStartTime().toInstant()
                .atZone(ZoneId.systemDefault()).toLocalTime();

        LocalTime checkInStart = startTime.minusMinutes(30);
        
        if (nowTime.isBefore(checkInStart)) {
            result.put("reason", "签到时间未到（预约开始前30分钟内可签到）");
            return result;
        }

        if (nowTime.isAfter(startTime)) {
            result.put("reason", "签到时间已过（只能在预约开始前30分钟内签到）");
            return result;
        }

        result.put("canCheckIn", true);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int processTimeoutReservations() {
        
        LocalTime nowTime = LocalTime.now();
        Date today = new Date();
        
        // 查找所有已超时的未签到预约
        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("reservation_status", 0) // 待签到状态
                .apply("end_time < {0}", nowTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                // 同时需要确保是今天的预约，通过reservation_time判断
                .apply("DATE(reservation_time) = DATE({0})", today);

        List<StudyRoomReservation> timeoutReservations = studyRoomReservationMapper.selectList(queryWrapper);
        
        int processedCount = 0;
        for (StudyRoomReservation reservation : timeoutReservations) {
            // 更新为超时状态
            reservation.setReservationStatus(3);
            studyRoomReservationMapper.updateById(reservation);
            
            // 释放座位
            Seat seat = seatMapper.selectById(reservation.getSeatId());
            if (seat != null) {
                seat.setSeatStatus(1); // 有空闲
                seatMapper.updateById(seat);
            }
            
            processedCount++;
        }
        
        return processedCount;
    }

    @Override
    public StudyRoomReservation getCurrentReservation(Long seatId) {
        
        if (seatId == null) {
            throw new BusinessException("座位ID不能为空");
        }

        LocalTime nowTime = LocalTime.now();
        Date today = new Date();
        
        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("seat_id", seatId)
                .eq("reservation_status", 1) // 已签到状态
                .apply("DATE(reservation_time) = DATE({0})", today) // 只查找今天的预约
                .apply("start_time <= {0}", nowTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                .apply("end_time >= {0}", nowTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                .orderByDesc("start_time")
                .last("LIMIT 1");
        
        return studyRoomReservationMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchCancelUserReservations(Long userId, String reason, Long operatorId, 
                                         String operatorName, String ip) {
        
        if (userId == null || operatorId == null) {
            throw new BusinessException("用户ID和操作人ID不能为空");
        }

        // 查找用户所有待签到的预约
        LocalTime nowTime = LocalTime.now();
        Date today = new Date();
        
        QueryWrapper<StudyRoomReservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId)
                .eq("reservation_status", 0) // 待签到状态
                .and(wrapper -> wrapper
                        // 今天且开始时间未到
                        .apply("DATE(reservation_time) = DATE({0})", today)
                        .apply("start_time >= {0}", nowTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .or()
                        // 或者未来日期的预约
                        .apply("DATE(reservation_time) > DATE({0})", today)
                );

        List<StudyRoomReservation> reservations = studyRoomReservationMapper.selectList(queryWrapper);
        
        int cancelledCount = 0;
        for (StudyRoomReservation reservation : reservations) {
            // 更新预约状态
            reservation.setReservationStatus(2); // 已取消
            studyRoomReservationMapper.updateById(reservation);
            
            // 释放座位
            Seat seat = seatMapper.selectById(reservation.getSeatId());
            if (seat != null) {
                seat.setSeatStatus(1); // 有空闲
                seatMapper.updateById(seat);
            }
            
            // 记录操作日志
            String logReason = reason != null ? reason : "批量取消用户预约";
            operationLogService.recordLog(operatorId, reservation.getSeatId(), 3, // 实体类型：3-座位
                    String.format("批量取消用户预约，原因：%s", logReason));
            
            cancelledCount++;
        }
        
        return cancelledCount;
    }
}